﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;
using SimpleIR;

using System.Xml;

namespace PInfoModel
{
	/// <summary>
	/// This class provides a wrapper for easy serialization of PIModel information.
	/// </summary>
	internal abstract class PInfoSerializer
	{
		private int m_tmc;
		internal readonly Dictionary<IRType, int> TypeMap;

		private int m_fmc;
		internal readonly Dictionary<IRMemberField, int> FieldMap;

		private int m_bmc;
		internal readonly Dictionary<IRBasicAccessPath, int> PathMap;

		private int m_rmc;
		internal readonly Dictionary<IRRootIdentifier, int> RootMap;

		private int m_smc;
		internal readonly Dictionary<string, int> StringMap;

		protected PInfoSerializer()
		{
			this.m_tmc = 0;
			this.TypeMap = new Dictionary<IRType, int>();

			this.m_fmc = 0;
			this.FieldMap = new Dictionary<IRMemberField, int>();

			this.m_bmc = 0;
			this.PathMap = new Dictionary<IRBasicAccessPath, int>();

			this.m_rmc = 0;
			this.RootMap = new Dictionary<IRRootIdentifier, int>();

			this.m_smc = 0;
			this.StringMap = new Dictionary<string, int>();
		}

		internal void WriteIRType(string ttag, IRType t)
		{
			if(!this.TypeMap.ContainsKey(t))
				this.TypeMap.Add(t, this.m_tmc++);

			this.WriteInt(ttag, this.TypeMap[t]);
		}

		internal void WriteIRField(string ftag, IRMemberField f)
		{
			if(!this.FieldMap.ContainsKey(f))
				this.FieldMap.Add(f, this.m_fmc++);

			this.WriteInt(ftag, this.FieldMap[f]);
		}

		internal void WriteIRBasicAccessPath(string ptag, IRBasicAccessPath bap)
		{
			if(!this.PathMap.ContainsKey(bap))
				this.PathMap.Add(bap, this.m_bmc++);

			this.WriteInt(ptag, this.PathMap[bap]);
		}

		internal void WriteIRRoot(string rtag, IRRootIdentifier r)
		{
			if(!this.RootMap.ContainsKey(r))
				this.RootMap.Add(r, this.m_rmc++);

			this.WriteInt(rtag, this.RootMap[r]);
		}

		internal int InternString(string tag)
		{
			if(!this.StringMap.ContainsKey(tag))
				this.StringMap.Add(tag, this.m_smc++);

			return this.StringMap[tag];
		}

		internal abstract void WriteStartTag(string tag);

		internal abstract void WriteEndTag(string tag);

		internal abstract void WriteCollectionStartTag(string lname, int count);

		internal abstract void WriteCollectionEndTag(string lname);

		internal abstract void WriteBool(string name, bool b);

		internal abstract void WriteInt(string name, int i);

		internal abstract void WriteString(string name, string val);
	}


	/// <summary>
	/// This class provides a wrapper for easy serialization of PIModel information in a XML format.
	/// </summary>
	internal sealed class PInfoSerializerXML : PInfoSerializer
	{
		private XmlWriter m_xw;

		internal PInfoSerializerXML(XmlWriter xw)
			: base()
		{ this.m_xw = xw; }

		internal override void WriteStartTag(string tag)
		{ this.m_xw.WriteStartElement(tag); }

		internal override void WriteEndTag(string tag)
		{ this.m_xw.WriteEndElement(); }

		internal override void WriteCollectionStartTag(string lname, int count)
		{
			this.WriteStartTag(lname);
			this.m_xw.WriteAttributeString("num", count.ToString());
		}

		internal override void WriteCollectionEndTag(string lname)
		{ this.WriteEndTag(lname); }

		internal override void WriteBool(string name, bool b)
		{ this.m_xw.WriteAttributeString(name, b.ToString()); }

		internal override void WriteInt(string name, int i)
		{ this.m_xw.WriteAttributeString(name, i.ToString()); }

		internal override void WriteString(string name, string val)
		{ this.m_xw.WriteAttributeString(name, val); }
	}

	/// <summary>
	/// This class provides a wrapper for easy serialization of PIModel information in a Binary format.
	/// </summary>
	internal sealed class PInfoSerializerBinary : PInfoSerializer
	{
		private System.IO.BinaryWriter m_bw;

		internal PInfoSerializerBinary(System.IO.BinaryWriter bw)
			: base()
		{ this.m_bw = bw; }

		internal override void WriteStartTag(string tag)
		{
			int tt = this.InternString(tag);
			this.m_bw.Write(tt); 
		}

		internal override void WriteEndTag(string tag)
		{
			int tt = -this.InternString(tag);
			this.m_bw.Write(tt); 
		}

		internal override void WriteCollectionStartTag(string lname, int count)
		{
			this.WriteStartTag(lname);
			this.m_bw.Write(count);
		}

		internal override void WriteCollectionEndTag(string lname)
		{ this.WriteEndTag(lname); }

		internal override void WriteBool(string name, bool b)
		{
			this.m_bw.Write(b ? 1 : 0);
		}

		internal override void WriteInt(string name, int i)
		{ 
			this.m_bw.Write(i); 
		}

		internal override void WriteString(string name, string val)
		{
			int sv = this.InternString(val);
			this.m_bw.Write(sv);
		}
	}
}
